#pragma once

#include <vector>
#include <atomic>

#include "macros.h"

namespace Common {

  /**
   * @brief 固定容量的无锁环形队列（Lock-Free Queue）。
   *
   *  - 模板参数 @tparam T 指定队列中元素的类型。
   *  - 内部以环形缓冲区形式存储元素，通过读/写索引实现循环利用。
   *  - 使用原子变量维护读写位置与元素数量，从而在多线程环境下减少锁竞争。
   *
   * ⚠️ 设计假设：
   *  - 使用者需要在外层控制生产者/消费者的同步语义；此实现未提供严格意义上的
   *    多生产者多消费者无锁保证。
   *  - 环形缓冲区容量固定；若写入速度超过读取速度且不做额外处理，可能覆盖尚未读取的数据。
   */
  template<typename T>
  class LFQueue final {
  public:
    /**
     * @brief 构造指定容量的环形队列。
     *
     * @param num_elems 预先分配的存储槽位数量。
     * @note 使用 std::vector<T> 进行底层存储，保证元素空间连续并便于缓存友好访问。
     */
    explicit LFQueue(std::size_t num_elems)
        : store_(num_elems, T()) /* 预分配 vector 容量，并以 T 的默认值初始化。 */ {
    }

    /**
     * @brief 获取当前可写入的位置指针。
     *
     * @return 指向可写槽位的原生指针。
     * @note 调用者负责在写入数据后显式调用 updateWriteIndex() 推进写指针。
     */
    auto getNextToWriteTo() noexcept {
      return &store_[next_write_index_];
    }

    /**
     * @brief 将写索引推进到下一个槽位，并更新元素计数。
     *
     * @note
     *  - 采用取模操作实现索引循环。
     *  - num_elements_++ 使用原子递增，保证多线程下计数语义正确。
     */
    auto updateWriteIndex() noexcept {
      next_write_index_ = (next_write_index_ + 1) % store_.size();
      num_elements_++;
    }

    /**
     * @brief 获取当前可读元素的指针。
     *
     * @return 若队列非空，返回指向当前读索引处元素的指针；否则返回 nullptr。
     * @note 调用者需要在消费元素后调用 updateReadIndex() 推进读指针。
     */
    auto getNextToRead() const noexcept -> const T * {
      return (size() ? &store_[next_read_index_] : nullptr);
    }

    /**
     * @brief 将读索引推进到下一个槽位，并递减元素计数。
     *
     * @note
     *  - 读索引同样采用取模实现循环。
     *  - 通过断言确保在合法的非空状态下执行读取，便于调试阶段捕获错误。
     */
    auto updateReadIndex() noexcept {
      next_read_index_ = (next_read_index_ + 1) % store_.size();
      ASSERT(num_elements_ != 0, "Read an invalid element in:" + std::to_string(pthread_self()));
      num_elements_--;
    }

    /**
     * @brief 当前队列中元素数量。
     *
     * @return 以原子方式读取的元素计数。
     */
    auto size() const noexcept {
      return num_elements_.load();
    }

    // 禁用默认构造、拷贝/移动构造与赋值，防止不受控的资源复制。
    LFQueue() = delete;
    LFQueue(const LFQueue &) = delete;
    LFQueue(const LFQueue &&) = delete;
    LFQueue &operator=(const LFQueue &) = delete;
    LFQueue &operator=(const LFQueue &&) = delete;

  private:
    std::vector<T> store_; ///< 环形缓冲区的实际存储容器。

    std::atomic<size_t> next_write_index_ = {0}; ///< 下一次写入的位置索引。
    std::atomic<size_t> next_read_index_ = {0};  ///< 下一次读取的位置索引。

    std::atomic<size_t> num_elements_ = {0};     ///< 当前已占用的元素数量。
  };

} // namespace Common